package com.wzb.mybatisplus.bitaction;

import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.Arrays;

public class BitcoinPrivateKeyGenerator {

    // Secp256k1曲线的阶 n (略小于 2^256)
    private static final BigInteger CURVE_ORDER = new BigInteger(
            "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16
    );

    public static void main(String[] args) {
        try {
            System.out.println("L2FHcXzMgpKATZYVFBdKxdjKbsWNiDZyhFGqFmCVKGJwzQYgLRJY".length());
            // 1. 生成一个密码学安全的随机私钥
            BigInteger privateKey = generateValidPrivateKey();
            System.out.println("生成的随机私钥 (十六进制):");
            System.out.println(privateKey.toString(16).toUpperCase());
            System.out.println();

            // 2. 将其转换为 WIF 压缩格式
            String wifCompressed = privateKeyToWIF(privateKey, true);
            System.out.println("对应的 WIF 压缩格式:");
            System.out.println(wifCompressed);
            System.out.println();

            // 3. (可选) 转换为 WIF 非压缩格式
            String wifUncompressed = privateKeyToWIF(privateKey, false);
            System.out.println("对应的 WIF 非压缩格式 (较少使用):");
            System.out.println(wifUncompressed);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 使用 SecureRandom 生成一个有效的比特币私钥
     */
    private static BigInteger generateValidPrivateKey() {
        SecureRandom secureRandom = new SecureRandom();
        BigInteger privateKey;

        // 循环，直到生成的私钥在有效范围内 [1, n-1]
        do {
            // 生成一个 256 位的随机数
            privateKey = new BigInteger(256, secureRandom);
        } while (privateKey.compareTo(BigInteger.ONE) < 0 ||
                privateKey.compareTo(CURVE_ORDER) >= 0);

        return privateKey;
    }

    /**
     * 将 BigInteger 类型的私钥转换为 WIF 格式
     * @param privateKey 私钥
     * @param compressed 是否使用压缩格式
     * @return WIF 字符串
     */
    private static String privateKeyToWIF(BigInteger privateKey, boolean compressed) {
        try {
            // 1. 在私钥前添加版本字节 (0x80 代表主网)
            byte[] versionedBytes = new byte[compressed ? 34 : 33]; // 如果压缩，总长34字节
            versionedBytes[0] = (byte) 0x80; // 主网前缀
            // 将私钥的字节数组拷贝到 versionedBytes 中
            byte[] privBytes = privateKey.toByteArray();
            int srcPos = Math.max(0, privBytes.length - 32); // 处理BigInteger可能带前导00的情况
            int length = Math.min(32, privBytes.length);
            System.arraycopy(privBytes, srcPos, versionedBytes, 33 - length, length);

            // 2. 如果要求压缩，在末尾添加 0x01 字节
            if (compressed) {
                versionedBytes[33] = (byte) 0x01;
            }

            // 3. 计算双重 SHA-256 校验和 (取前4个字节)
            byte[] checksum = doubleSHA256(versionedBytes);

            // 4. 将校验和附加到版本化私钥后面
            byte[] wifBytes = new byte[versionedBytes.length + 4];
            System.arraycopy(versionedBytes, 0, wifBytes, 0, versionedBytes.length);
            System.arraycopy(checksum, 0, wifBytes, versionedBytes.length, 4);

            // 5. 对整个结果进行 Base58 编码
            return Base58.encode(wifBytes);
        } catch (Exception e) {
            throw new RuntimeException("Error converting private key to WIF", e);
        }
    }

    /**
     * 计算数据的双重 SHA-256 哈希
     */
    private static byte[] doubleSHA256(byte[] data) {
        try {
            java.security.MessageDigest digest = java.security.MessageDigest.getInstance("SHA-256");
            byte[] hash1 = digest.digest(data);
            byte[] hash2 = digest.digest(hash1);
            // 返回前4个字节作为校验和
            return Arrays.copyOfRange(hash2, 0, 4);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Base58 编码工具类
     * (比特币使用的Base58，去掉了容易混淆的 0, O, I, l 等字符)
     */
    public static class Base58 {
        private static final char[] ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".toCharArray();
        private static final BigInteger BASE = BigInteger.valueOf(58);

        public static String encode(byte[] input) {
            BigInteger value = new BigInteger(1, input);
            StringBuilder sb = new StringBuilder();
            while (value.compareTo(BASE) >= 0) {
                BigInteger[] divmod = value.divideAndRemainder(BASE);
                sb.append(ALPHABET[divmod[1].intValue()]);
                value = divmod[0];
            }
            sb.append(ALPHABET[value.intValue()]);

            // 处理前导零字节
            for (int i = 0; i < input.length && input[i] == 0; i++) {
                sb.append(ALPHABET[0]);
            }
            return sb.reverse().toString();
        }
    }
}